import pandas as pd
import numpy as np
from pathlib import Path
import warnings
import os

def check_overlap(period1_start, period1_end, period2_start, period2_end):
    """检查两个时间段是否有完全重叠的情况
    完全重叠的定义：一个时间段的开始日期在另一个时间段的起止日期之间
    首尾相接的情况（如10.1-10.3和10.3-10.6）被视为正常
    """
    # 将时间转换为日期，去除时分秒
    period1_start = pd.to_datetime(period1_start).date()
    period1_end = pd.to_datetime(period1_end).date()
    period2_start = pd.to_datetime(period2_start).date()
    period2_end = pd.to_datetime(period2_end).date()
    
    # 检查period2的开始日期是否在period1的日期范围内（不包括首尾相接的情况）
    if period1_start < period2_start < period1_end:
        return True
    # 检查period1的开始日期是否在period2的日期范围内（不包括首尾相接的情况）
    if period2_start < period1_start < period2_end:
        return True
    return False

def main(once = False):
    """主函数：分析交通补助报销不合理数据"""
    try:
        # 忽略警告
        warnings.filterwarnings('ignore')
        
        # 设置数据文件路径
        data_dir = Path("data")
        alldata_dir = data_dir / "alldata"
        
        # 确保目录存在
        alldata_dir.mkdir(parents=True, exist_ok=True)
        
        # 读取源数据
        source_file = data_dir / "差旅费城市间交通费.xlsx"
        travel_file = data_dir / "差旅报销行程明细(商旅).xlsx"
        
        if not source_file.exists():
            raise FileNotFoundError(f"源数据文件不存在: {source_file}")
        if not travel_file.exists():
            raise FileNotFoundError(f"行程明细文件不存在: {travel_file}")
            
        print("正在读取源数据...")
        df = pd.read_excel(source_file)
        travel_df = pd.read_excel(travel_file)
        
        # 数据预处理
        print("正在处理数据...")
        
        # 确保时间列为datetime类型
        df['出发时间'] = pd.to_datetime(df['出发时间'])
        df['到达时间'] = pd.to_datetime(df['到达时间'])
        
        # 首先按唯一标识和员工编号分组，计算每组的最早出发时间和最晚到达时间
        group_summary = df.groupby(['唯一标识', '员工编号']).agg({
            '出发时间': 'min',
            '到达时间': 'max'
        }).reset_index()
        
        # 重命名列
        group_summary.columns = ['唯一标识', '员工编号', '组内最早出发时间', '组内最晚到达时间']
        
        # 创建一个字典来存储每个员工的所有组
        employee_groups = {}
        for _, row in group_summary.iterrows():
            emp_id = row['员工编号']
            if emp_id not in employee_groups:
                employee_groups[emp_id] = []
            employee_groups[emp_id].append(row)
        
        # 创建一个空的列表来存储结果
        result_rows = []
        
        # 对每个员工，比较其不同组之间的时间重叠
        for emp_id, groups in employee_groups.items():
            # 如果员工只有一个组，跳过
            if len(groups) <= 1:
                continue
                
            # 比较该员工的每对不同组之间的时间重叠
            overlapped_pairs = []  # 用于存储重叠的组对
            for i in range(len(groups)):
                for j in range(i + 1, len(groups)):
                    if check_overlap(
                        groups[i]['组内最早出发时间'],
                        groups[i]['组内最晚到达时间'],
                        groups[j]['组内最早出发时间'],
                        groups[j]['组内最晚到达时间']
                    ):
                        # 记录重叠的组对
                        overlapped_pairs.append((groups[i], groups[j]))
            
            # 如果找到重叠的组，添加这些组的所有记录到结果中
            if overlapped_pairs:
                # 创建重叠组的映射关系
                overlap_info = {}
                for group1, group2 in overlapped_pairs:
                    unique_id1 = group1['唯一标识']
                    unique_id2 = group2['唯一标识']
                    
                    # 为每个组记录与之重叠的组信息
                    if unique_id1 not in overlap_info:
                        overlap_info[unique_id1] = []
                    if unique_id2 not in overlap_info:
                        overlap_info[unique_id2] = []
                    
                    overlap_info[unique_id1].append({
                        '重叠唯一标识': unique_id2,
                        '重叠最早出发时间': group2['组内最早出发时间'],
                        '重叠最晚到达时间': group2['组内最晚到达时间']
                    })
                    overlap_info[unique_id2].append({
                        '重叠唯一标识': unique_id1,
                        '重叠最早出发时间': group1['组内最早出发时间'],
                        '重叠最晚到达时间': group1['组内最晚到达时间']
                    })
                
                # 获取所有重叠组的原始数据
                for unique_id, overlaps in overlap_info.items():
                    group_data = df[
                        (df['员工编号'] == emp_id) & 
                        (df['唯一标识'] == unique_id)
                    ].copy()
                    
                    # 添加组的时间范围信息
                    group_info = next(g for g in groups if g['唯一标识'] == unique_id)
                    group_data['组内最早出发时间'] = group_info['组内最早出发时间']
                    group_data['组内最晚到达时间'] = group_info['组内最晚到达时间']
                    
                    # 添加重叠信息
                    overlap_ids = [o['重叠唯一标识'] for o in overlaps]
                    overlap_start_times = [o['重叠最早出发时间'] for o in overlaps]
                    overlap_end_times = [o['重叠最晚到达时间'] for o in overlaps]
                    
                    # 获取重叠组的单据编号
                    overlap_doc_numbers = df[
                        (df['员工编号'] == emp_id) & 
                        (df['唯一标识'].isin(overlap_ids))
                    ]['单据编号'].unique()
                    
                    group_data['重叠单据编号'] = '、'.join(map(str, overlap_doc_numbers))
                    group_data['重叠最早出发时间'] = min(overlap_start_times)
                    group_data['重叠最晚到达时间'] = max(overlap_end_times)
                    
                    # 对组内数据按出发时间排序
                    group_data = group_data.sort_values('出发时间')
                    
                    # 获取申请事由
                    travel_reasons = travel_df[travel_df['唯一标识'] == unique_id]['申请事由'].fillna('').astype(str).tolist()
                    group_data['申请事由'] = '、'.join(travel_reasons)
                    
                    result_rows.append(group_data)
        
        # 创建结果DataFrame
        if result_rows:
            result_df = pd.concat(result_rows, ignore_index=True)
            
            # 筛选培训相关的记录
            training_df = result_df
            if '申请事由' in result_df.columns:
                training_mask = result_df['申请事由'].fillna('').astype(str).str.contains('培训')
                training_df = result_df[training_mask].copy()
                print(f"\n总不合理记录数: {len(result_df)}")
                print(f"其中培训相关记录数: {len(training_df)}")
                print(f"非培训记录数: {len(result_df) - len(training_df)}")
            else:
                print("\n警告：数据中没有'申请事由'列，无法筛选培训记录")
            
            # 先按组排序（员工编号和唯一标识），再按组内出发时间排序
            # 为了确保组的顺序稳定，我们先给每个组分配一个序号
            group_order = (training_df.groupby(['员工编号', '唯一标识'])['组内最早出发时间']
                         .min()
                         .reset_index()
                         .sort_values(['员工编号', '组内最早出发时间'])
                         .reset_index()
                         .rename(columns={'index': 'group_order'}))
            
            # 将序号合并到主数据中
            training_df = training_df.merge(
                group_order[['员工编号', '唯一标识', 'group_order']], 
                on=['员工编号', '唯一标识']
            )
            
            # 按组序号和组内出发时间排序
            training_df = training_df.sort_values(['group_order', '出发时间'])
            
            # 删除辅助排序列
            training_df = training_df.drop('group_order', axis=1)
            
            # 格式化时间列，只保留年月日
            training_df['出发时间'] = training_df['出发时间'].dt.strftime('%Y-%m-%d')
            training_df['到达时间'] = training_df['到达时间'].dt.strftime('%Y-%m-%d')
            training_df['组内最早出发时间'] = training_df['组内最早出发时间'].dt.strftime('%Y-%m-%d')
            training_df['组内最晚到达时间'] = training_df['组内最晚到达时间'].dt.strftime('%Y-%m-%d')
            training_df['重叠最早出发时间'] = training_df['重叠最早出发时间'].dt.strftime('%Y-%m-%d')
            training_df['重叠最晚到达时间'] = training_df['重叠最晚到达时间'].dt.strftime('%Y-%m-%d')

            if once:
                return training_df

            # 保存结果
            output_file = alldata_dir / "交通补助报销不合理分析结果(培训申请).xlsx"
            print(f"正在保存分析结果到: {output_file}")
            
            # 保存为Excel文件
            training_df.to_excel(output_file, index=False)
            print("分析完成！")
            
            # 打印统计信息
            total_cases = len(training_df.groupby(['员工编号', '唯一标识']))  # 每个员工的每个组算一次
            total_employees = len(training_df['员工编号'].unique())
            print(f"\n统计信息:")
            print(f"发现培训相关不合理报销组数: {total_cases}")
            print(f"涉及员工人数: {total_employees}")
            
        else:
            print("未发现交通补助报销不合理的数据。")
        
        return True
        
    except Exception as e:
        print(f"处理过程中出现错误: {str(e)}")
        return False

if __name__ == "__main__":
    main() 